﻿using Common.AspNetCore;
using Common.Infrastructure;
using Common.RunModels.FCP;
using FCP.Api.Models;
using FCP.Api.Repository;
using FCP.Data.Entity;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace FCP.Api.Service
{
    public class FCPInitService : CommonService
    {
        private readonly FCPService fCPService;
        private readonly string lang;
        private readonly FCPRepository fcpRepository;
        public FCPInitService(IServiceProvider provider, FCPService fCP, IConfiguration c, FCPRepository fcp) : base(provider)
        {
            this.fCPService = fCP;
            this.lang = !string.IsNullOrEmpty(c["DefaultLang"]) ? c["DefaultLang"] : "CN";
            this.fcpRepository = fcp;
        }

        public async Task<FCPInitReponse> InitOrgAsync(FCPInitParam param)
        {
            LibCheckNullUtils.CheckNull(param.DestOrgId, "destOrgId");
            LibCheckNullUtils.CheckNull(param.SrcOrgId, "SrcOrgId");
            if (param.SrcOrgId == param.DestOrgId)
            {
                return new FCPInitReponse();
            }

            FormInitAddEntityModel model = new FormInitAddEntityModel()
            {
                SrcDestIdRels = new Dictionary<string, string>(),
                DestOrgId = param.DestOrgId,
                SrcOrgId = param.SrcOrgId,
            };
            var forms = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_form>(t => t.org_id == param.SrcOrgId);
            var destforms = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_form>(t => t.org_id == param.DestOrgId);
            if (destforms.Any())
            {
                FCPInitReponse ret = new FCPInitReponse();
                destforms.ForEach(t =>
                {
                    ret.Forms.Add(new FCPInitFormReponse() { SrcFormId = forms.FirstOrDefault(t1 => t1.code == t.code)?.id, DestFormId = t.id });
                });
                return ret;
            }

            var ret1 = await DoInitFormConfigAsync(model, forms, destforms, null);
            return ret1;
        }

        public async Task<FCPInitReponse> SyncFormConfigAsync(FCPInitByFormParam param)
        {
            LibCheckNullUtils.CheckNull(param.DestOrgId, "destOrgId");
            LibCheckNullUtils.CheckNull(param.SrcOrgId, "SrcOrgId");
            if (param.SrcOrgId == param.DestOrgId || param.SrcFormIds == null || !param.SrcFormIds.Any())
            {
                return new FCPInitReponse();
            }

            FormInitAddEntityModel model = new FormInitAddEntityModel()
            {
                SrcDestIdRels = new Dictionary<string, string>(),
                DestOrgId = param.DestOrgId,
                SrcOrgId = param.SrcOrgId,
            };
            var forms = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_form>(param.SrcFormIds);
            var formCodes = forms.Select(t => t.code).ToList(); 
            var destforms = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_form>(t => formCodes.Contains(t.code) && t.org_id == param.DestOrgId);

            model.SrcFormIds = forms.Select(t => t.id).ToList();
            model.DestFormIds = destforms.Select(t => t.id).ToList();
            var ret1 = await DoInitFormConfigAsync(model, forms, destforms, null);
            return ret1;
        }


        public async Task<FCPInitReponse> SyncFormConfigBySelfFormAsync(FCPInitBySelfFormParam param)
        { 
            LibCheckNullUtils.CheckNull(param.SrcOrgId, "SrcOrgId");
            if (param.Details == null || !param.Details.Any())
            {
                return new FCPInitReponse();
            }

            FormInitAddEntityModel model = new FormInitAddEntityModel()
            {
                SrcDestIdRels = new Dictionary<string, string>(),
                DestOrgId = param.SrcOrgId,
                SrcOrgId = param.SrcOrgId,
            };
            var forms = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_form>(param.Details.Select(t => t.SrcFormId).ToList());
            var formCodes = param.Details.Select(t => t.DestFormCode).ToList();
            var destforms = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_form>(t => formCodes.Contains(t.code) && t.org_id == param.SrcOrgId);

            Dictionary<string, string> formcoderels = new Dictionary<string, string>();

            List<t_form> relForms = new List<t_form>();

            foreach(var form in forms)
            {
                var s = param.Details.FirstOrDefault(t => t.SrcFormId == form.id);
                if (s == null || !destforms.Any(t1 => t1.code == s.DestFormCode))
                {
                    relForms.Add(form);
                }
            }

            model.SrcFormIds = relForms.Select(t => t.id).ToList();
            model.DestFormIds = destforms.Select(t => t.id).ToList();

            param.Details.ForEach(t =>
            {
                formcoderels[t.SrcFormId] = t.DestFormCode; 
            });

            if (!relForms.Any())
            {
                return null;
            }

            var ret1 = await DoInitFormConfigAsync(model, relForms, destforms, formcoderels);
            return ret1;
        }


        public async Task<FCPInitReponse> InitSysAsync(FCPInitParam param)
        {
            FCPInitReponse ret = new FCPInitReponse();
            var form1 = new t_form()
            {
                code = "001",
                name = "自定义",
                form_type = 0,
                org_id = param.DestOrgId,
            };
            this.SetEntityId(form1);
            ret.Forms.Add(new FCPInitFormReponse() { DestFormId = form1.id });

            var custom1 = new t_custom()
            {
                fcp_form_id = form1.id,
                org_id = form1.org_id,
            };
            this.SetEntityId(custom1);


            var form2 = new t_form()
            {
                code = "002",
                name = "列表",
                form_type = 1,
                org_id = param.DestOrgId,
            };
            this.SetEntityId(form2);
            ret.Forms.Add(new FCPInitFormReponse() { DestFormId = form2.id });

            var table1 = new t_table()
            {
                org_id = form2.org_id,
                entity_name = "m_product",
                fcp_form_id = form2.id,
            };
            this.SetEntityId(table1);

            var tableField1 = new t_table_field()
            {
                fcp_form_id = form2.id,
                org_id = form2.org_id,
                table_id = table1.id,
                field_name = "name",
            };
            this.SetEntityId(tableField1);

            var tableBtn1 = new t_table_btn()
            {
                table_id = table1.id,
                org_id = form2.org_id,
                fcp_form_id = form2.id,
                btn_type = 2,
            };
            this.SetEntityId(tableBtn1);

            var tableBtn2 = new t_table_btn()
            {
                table_id = table1.id,
                org_id = form2.org_id,
                fcp_form_id = form2.id,
                btn_type = 3,
            };
            this.SetEntityId(tableBtn2);


            var form3 = new t_form()
            {
                code = "003",
                name = "编辑",
                form_type = 2,
                org_id = param.DestOrgId,
            };
            this.SetEntityId(form3);

            ret.Forms.Add(new FCPInitFormReponse() { DestFormId = form3.id });
            var edit1 = new t_edit()
            {
                org_id = form3.org_id,
                entity_name = "m_product",
                fcp_form_id = form3.id,
            };
            this.SetEntityId(edit1);

            var editField1 = new t_edit_field()
            {
                fcp_form_id = form3.id,
                org_id = form3.id,
                edit_id = edit1.id,
                field_name = "name",
            };
            this.SetEntityId(editField1);

            var editBtn1 = new t_edit_btn()
            {
                edit_id = edit1.id,
                org_id = form3.org_id,
                fcp_form_id = form3.id,
                btn_type = 11,
            };
            this.SetEntityId(editBtn1);


            await this.fcpRepository.CommitChangesByCommonAsync(() =>
            {

                this.fcpRepository.CommonRepository.AddEntity(form1);
                this.fcpRepository.CommonRepository.AddEntity(custom1);
                this.fcpRepository.CommonRepository.AddEntity(form2);
                this.fcpRepository.CommonRepository.AddEntity(form3);
                this.fcpRepository.CommonRepository.AddEntity(table1);
                this.fcpRepository.CommonRepository.AddEntity(tableField1);
                this.fcpRepository.CommonRepository.AddEntity(tableBtn1);
                this.fcpRepository.CommonRepository.AddEntity(tableBtn2);
                this.fcpRepository.CommonRepository.AddEntity(edit1);
                this.fcpRepository.CommonRepository.AddEntity(editField1);
                this.fcpRepository.CommonRepository.AddEntity(editBtn1);

            });
            return ret;
        }

        class FormInitAddEntityModel
        {
            public string SrcOrgId { get; set; }

            public string DestOrgId { get; set; }

            public List<string> SrcFormIds { get; set; }

            public List<string> DestFormIds { get; set; }

            public Dictionary<string, string> SrcDestIdRels { get; set; }

            public List<t_label> SrcLabels { get; set; }
            public List<t_label_detail> SrcLabelDetails { get; set; }

            public List<t_label> DestLabels { get; set; }
            public List<t_label_detail> DestLabelDetails { get; set; }


            public List<t_label> AddDestLabels { get; set; }
            public List<t_label_detail> AddDestLabelDetails { get; set; }


            public List<t_label> UpdateDestLabels { get; set; }
            public List<t_label_detail> UpdateDestLabelDetails { get; set; }
        }


        private async Task DoAddToDestAsync<T>(FormInitAddEntityModel model, List<T> destEntities, List<T> updatedestEntities,
            string[] relFieldNames=null,string[] labelFieldNames=null, Func<T,List<T>,List<string>,string, T> updateAction = null, Action<T,T> action=null)
             where T : t_fcpBase, new()
        {
            Expression<Func<T, bool>> srcpredicate = t => t.org_id == model.SrcOrgId;
            if (model.SrcFormIds != null && model.SrcFormIds.Any())
            {
                srcpredicate = srcpredicate.And(t => model.SrcFormIds.Contains(t.fcp_form_id));
            }

            var entitys=await this.fcpRepository.CommonRepository.GetEntitiesAsync<T>(srcpredicate);
            if (!entitys.Any()) return;

            Expression<Func<T, bool>> destpredicate = t => t.org_id == model.DestOrgId;
            if (model.DestFormIds != null && model.DestFormIds.Any())
            {
                destpredicate = destpredicate.And(t => model.DestFormIds.Contains(t.fcp_form_id));
            }

            var destentitys = await this.fcpRepository.CommonRepository.GetEntitiesAsync<T>(destpredicate); 


            var type = typeof(T); 
            foreach(var s in entitys)
            {
                T dest = null;
                string destFormId = null;
                if (updateAction != null)
                {
                    List<string> relfields = new List<string>();
                    if (relFieldNames != null && relFieldNames.Any())
                    {
                        foreach (var f in relFieldNames)
                        {
                            var srcP = type.GetProperty(f);
                            var destP = type.GetProperty(f);
                            if (srcP != null && srcP.PropertyType == destP.PropertyType)
                            {
                                var value = LibSysUtils.ToString(srcP.GetValue(s, null));
                                if (value != null && model.SrcDestIdRels.TryGetValue(value, out string destId))
                                {
                                    relfields.Add(destId);
                                }
                                else
                                {
                                    relfields.Add("");
                                }
                            }
                            else
                            {
                                relfields.Add("");
                            }
                        }
                    }

                    model.SrcDestIdRels.TryGetValue(s.fcp_form_id, out destFormId);
                    dest = updateAction(s, destentitys, relfields, destFormId); 
                }
                if (dest == null)
                {
                    dest = new T();
                    this.SetEntityId(dest);
                    destEntities.Add(dest);
                }
                else
                {
                    if (!updatedestEntities.Any(t1 => t1.id == dest.id))
                    {
                        updatedestEntities.Add(dest);
                    }
                }

                model.SrcDestIdRels[s.id] = dest.id;
                LibSysUtils.CopyObject(dest, s);
                dest.org_id = model.DestOrgId;  
                if (model.SrcDestIdRels.TryGetValue(s.fcp_form_id, out destFormId))
                    dest.fcp_form_id = destFormId;

                ToDoHandleEntity(type, s, dest, model, relFieldNames, labelFieldNames);
                if (action != null)
                {
                    action(s, dest);
                }
            } 
        }

        private async Task DoAddToDestByTreeAsync<T>(FormInitAddEntityModel model, List<T> destEntities, List<T> updatedestEntities,
           string[] relFieldNames = null, string[] labelFieldNames = null, Func<T, List<T>, List<string>, string, T> updateAction = null, Action<T, T> action = null)
           where T : t_fcpTreeBase, new()
        {
            Expression<Func<T, bool>> predicate = t => t.org_id == model.SrcOrgId;
            if (model.SrcFormIds != null && model.SrcFormIds.Any())
            {
                predicate = predicate.And(t => model.SrcFormIds.Contains(t.fcp_form_id));
            }

            var entitys = await this.fcpRepository.CommonRepository.GetEntitiesAsync<T>(predicate);
            if (!entitys.Any()) return;

            Expression<Func<T, bool>> destpredicate = t => t.org_id == model.DestOrgId;
            if (model.DestFormIds != null && model.DestFormIds.Any())
            {
                destpredicate = destpredicate.And(t => model.DestFormIds.Contains(t.fcp_form_id));
            }

            var destentitys = await this.fcpRepository.CommonRepository.GetEntitiesAsync<T>(destpredicate);


            await DoInterAddEntityToDestListByTreeAsync<T>(model, null, null, entitys, destentitys, destEntities, updatedestEntities, labelFieldNames, relFieldNames, updateAction, action);
        }

        private async Task DoInterAddEntityToDestListByTreeAsync<T>(FormInitAddEntityModel model, 
            string srcParentId, string destParentId,
            List<T> srcEntities, List<T> destentitys, List<T> adddestEntities, List<T> updatedestEntities, string[] relFieldNames = null, string[] labelFieldNames = null, Func<T, List<T>, List<string>, string, T> updateAction = null, Action<T, T> action = null)
         where T : t_fcpTreeBase, new()
        {
            var entitys = srcEntities.Where(t => t.parent_id == srcParentId);
            var type = typeof(T);
            foreach (var s in entitys)
            {
                T dest = null;

                string destFormId = null;
                if (updateAction != null)
                {
                    List<string> relfields = new List<string>();
                    if (relFieldNames != null && relFieldNames.Any())
                    {
                        foreach (var f in relFieldNames)
                        {
                            var srcP = type.GetProperty(f);
                            var destP = type.GetProperty(f);
                            if (srcP != null && srcP.PropertyType == destP.PropertyType)
                            {
                                var value = LibSysUtils.ToString(srcP.GetValue(s, null));
                                if (value != null && model.SrcDestIdRels.TryGetValue(value, out string destId))
                                {
                                    relfields.Add(destId);
                                }
                                else
                                {
                                    relfields.Add("");
                                }
                            }
                            else
                            {
                                relfields.Add("");
                            }
                        }
                    }

                    model.SrcDestIdRels.TryGetValue(s.fcp_form_id, out destFormId);
                    dest = updateAction(s, destentitys, relfields, destFormId);
                }
                if (dest == null)
                {
                    dest = new T();
                    this.SetEntityId(dest);
                    adddestEntities.Add(dest);
                }
                else
                {
                    updatedestEntities.Add(dest);
                }
                 
                model.SrcDestIdRels[s.id] = dest.id;
                LibSysUtils.CopyObject(dest, s);
                dest.org_id = model.DestOrgId; 
                if (model.SrcDestIdRels.TryGetValue(s.fcp_form_id, out destFormId))
                    dest.fcp_form_id = destFormId;
                ToDoHandleEntity(type, s, dest, model, relFieldNames, labelFieldNames);
                if (action != null)
                {
                    action(s, dest);
                }

                if (destParentId != null)
                    dest.parent_id = destParentId;

                await DoInterAddEntityToDestListByTreeAsync(model, s.id, dest.id, srcEntities, destentitys, adddestEntities, updatedestEntities, relFieldNames, labelFieldNames, updateAction, action);
            }
        }

        private void ToDoHandleEntity(Type type,object s,object dest, FormInitAddEntityModel model, string[] relFieldNames, string[] labelFieldNames)
        {
            if (relFieldNames != null && relFieldNames.Any())
            {
                foreach (var f in relFieldNames)
                {
                    var srcP = type.GetProperty(f);
                    var destP = type.GetProperty(f);
                    if (srcP != null && srcP.PropertyType == destP.PropertyType)
                    {
                        var value = LibSysUtils.ToString(srcP.GetValue(s, null));
                        if (value != null && model.SrcDestIdRels.TryGetValue(value, out string destId))
                            destP.SetValue(dest, destId, null);
                    }
                }
            }

            if (labelFieldNames != null && labelFieldNames.Any())
            {
                foreach (var f in labelFieldNames)
                {
                    var srcP = type.GetProperty(f);
                    var destP = type.GetProperty(f);
                    if (srcP != null && srcP.PropertyType == destP.PropertyType)
                    {
                        var value = LibSysUtils.ToString(srcP.GetValue(s, null));
                        var srcl = model.SrcLabels.FirstOrDefault(t => t.id == value);
                        if (srcl != null)
                        {
                            var destvalue = LibSysUtils.ToString(destP.GetValue(dest, null));
                            var destL = destvalue != value ? model.DestLabels?.FirstOrDefault(t => t.id == destvalue) : null;
                            if (destL == null)
                            {
                                destL = new t_label();
                                this.SetEntityId(destL);
                                LibSysUtils.CopyObject(destL, srcl);
                                destL.org_id = model.DestOrgId;
                                model.DestLabels.Add(destL);
                                model.AddDestLabels.Add(destL);
                                destP.SetValue(dest, destL.id);
                            }
                            else
                            { 
                            }
                             
                          

                            model.SrcLabelDetails.Where(t1 => t1.label_id == value).ForEach(t1 =>
                            {
                                var destld = model.DestLabelDetails?.FirstOrDefault(t2 => t2.label_id == destL.id && t2.lang == t1.lang);
                                if (destld == null)
                                {
                                    destld = new t_label_detail(); 
                                    LibSysUtils.CopyObject(destld, t1);
                                    this.SetEntityId(destld);
                                    destld.org_id = model.DestOrgId;
                                    destld.label_id = destL.id;
                                    model.DestLabelDetails.Add(destld);
                                    model.AddDestLabelDetails.Add(destld);
                                }
                                else
                                {
                                    destld.label = t1.label;
                                    model.UpdateDestLabelDetails.Add(destld);
                                }
                              
                            });

                            destP.SetValue(dest, destL.id, null);
                        }

                    }
                }
            }
        }


        private async Task<FCPInitReponse> DoInitFormConfigAsync(FormInitAddEntityModel model,List<t_form> forms, List<t_form> destforms, Dictionary<string,string> formCodeRels)
        {
            FCPInitReponse ret = new FCPInitReponse();
            SaveInitModel save = new SaveInitModel();
            model.SrcLabels = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_label>(t => t.org_id == model.SrcOrgId);
            model.SrcLabelDetails = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_label_detail>(t => t.org_id == model.SrcOrgId);

            model.DestLabels = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_label>(t => t.org_id == model.DestOrgId);
            model.DestLabelDetails = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_label_detail>(t => t.org_id == model.DestOrgId);

            model.AddDestLabelDetails = save.AddLabelDetails;
            model.AddDestLabels = save.AddLabels;
            model.UpdateDestLabelDetails = save.UpdateLabelDetails;
            model.UpdateDestLabels = save.UpdateLabels;

            foreach (var s in forms)
            {
                var dset = destforms != null ? destforms.FirstOrDefault(t => t.code == s.code && t.org_id == model.DestOrgId) : null;
                if (dset == null)
                {
                    dset = new t_form() { org_id = model.DestOrgId };
                    LibSysUtils.CopyObject(dset, s);
                    dset.org_id = model.DestOrgId;
                    if (formCodeRels != null && formCodeRels.TryGetValue(s.id, out string destCode))
                    {
                        dset.code = destCode;
                    }

                    this.SetEntityId(dset);
                    save.AddForms.Add(dset);
                }

                model.SrcDestIdRels[s.id] = dset.id;
                ret.Forms.Add(new FCPInitFormReponse() { SrcFormId = s.id, DestFormId = dset.id });
            }

            #region 按表添加数据
            await DoAddToDestAsync<t_chart>(model, save.AddCharts, save.UpdateCharts, null, new string[] { "label_label_id" }, (src, destList,rels,formId) => destList?.FirstOrDefault(t => t.code == src.code && t.fcp_form_id == formId));

            await DoAddToDestAsync<t_custom>(model, save.AddCustoms, save.UpdateCustoms, null, new string[] { "label_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.fcp_form_id == formId));
            await DoAddToDestAsync<t_custom_btn>(model, save.AddCustomBtns, save.UpdateCustomBtns, new string[] { "custom_id" }, new string[] { "btn_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code &&t.custom_id==rels[0]));

            await DoAddToDestByTreeAsync<t_edit>(model, save.AddEdits, save.UpdateEdits, null, new string[] { "label_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.fcp_form_id == formId));
            await DoAddToDestAsync<t_edit_btn>(model, save.AddEditBtns, save.UpdateEditBtns, new string[] { "edit_id" }, new string[] { "btn_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code&&t.edit_id==rels[0]));
            await DoAddToDestAsync<t_edit_panel>(model, save.AddEditPanels, save.UpdateEditPanels, new string[] { "edit_id" }, new string[] { "btn_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.num == src.num && t.edit_id == rels[0]));
            await DoAddToDestAsync<t_edit_field>(model, save.AddEditFields, save.UpdateEditFields, new string[] { "edit_id", "edit_panel_id" }, new string[] { "field_label_id", "prompt_info_label_id", "verify_error_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.edit_id == rels[0]));
            await DoAddToDestByTreeAsync<t_edit_field_filter_group>(model, save.AddEditFieldFilterGroups, save.UpdateEditFieldFilterGroups, new string[] { "edit_id", "edit_field_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.edit_field_id == rels[1]));
            await DoAddToDestAsync<t_edit_field_filter_field>(model, save.AddEditFieldFilterFields, save.UpdateEditFieldFilterFields, new string[] { "edit_id", "edit_field_id", "edit_field_filter_group_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.edit_field_filter_group_id == rels[2]));
            await DoAddToDestAsync<t_edit_field_map>(model, save.AddEditFieldMaps,save.UpdateEditFieldMaps, new string[] { "edit_field_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.src_nav == src.src_nav && t.edit_field_id == rels[0]));
            await DoAddToDestAsync<t_edit_field_map_detail>(model, save.AddEditFieldMapDetails, save.UpdateEditFieldMapDetails, new string[] { "edit_field_map_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.src_field_name == src.src_field_name && t.edit_field_map_id == rels[0]));

            await DoAddToDestAsync<t_search>(model, save.AddSearchs, save.UpdateSearchs, null, new string[] { "label_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.fcp_form_id == formId));
            await DoAddToDestAsync<t_search_field>(model, save.AddSearchFeilds, save.UpdateSearchFeilds, new string[] { "search_id" }, new string[] { "field_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.search_id == rels[0]));
            await DoAddToDestByTreeAsync<t_search_field_filter_group>(model, save.AddSearchFieldFilterGroups, save.UpdateSearchFieldFilterGroups, new string[] { "search_id", "search_field_id" }, null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.search_field_id == rels[1]));
            await DoAddToDestAsync<t_search_field_filter_field>(model, save.AddSearchFieldFilterFields, save.UpdateSearchFieldFilterFields, new string[] { "search_id", "search_field_id", "search_field_filter_group_id" }, null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.search_field_filter_group_id == rels[2]));


            await DoAddToDestByTreeAsync<t_table>(model, save.AddTables, save.UpdateTables, null, new string[] { "label_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.fcp_form_id == formId));
            await DoAddToDestAsync<t_table_btn>(model, save.AddTableBtns, save.UpdateTableBtns, new string[] { "table_id" }, new string[] { "btn_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.table_id == rels[0]));
            await DoAddToDestAsync<t_table_panel>(model, save.AddTablePanel, save.UpdateTablePanel, new string[] { "table_id" }, new string[] { "label_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.num == src.num && t.table_id == rels[0]));
            await DoAddToDestAsync<t_table_field>(model, save.AddTableFields, save.UpdateTableFields, new string[] { "table_id", "table_panel_id" }, new string[] { "field_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.table_id == rels[0]));
            await DoAddToDestByTreeAsync<t_table_field_filter_group>(model, save.AddTableFieldFilterGroups, save.UpdateTableFieldFilterGroups, new string[] { "table_id", "table_field_id" }, null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.table_field_id == rels[1]));
            await DoAddToDestAsync<t_table_field_filter_field>(model, save.AddTableFieldFilterFields, save.UpdateTableFieldFilterFields, new string[] { "table_id", "table_field_id", "table_field_filter_group_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.table_field_filter_group_id == rels[2]));
            await DoAddToDestByTreeAsync<t_table_filter_group>(model, save.AddTableFilterGroups, save.UpdateTableFilterGroups, new string[] { "table_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.table_id == rels[0]));
            await DoAddToDestAsync<t_table_filter_field>(model, save.AddTabelFilterFields, save.UpdateTabelFilterFields, new string[] { "table_id", "table_filter_group_id" },null, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.table_filter_group_id == rels[1]));


            await DoAddToDestAsync<t_tree>(model, save.AddTree, save.UpdateTree, null, new string[] { "label_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.fcp_form_id == formId));
            await DoAddToDestAsync<t_tree_btn>(model, save.AddTreeBtns, save.UpdateTreeBtns, new string[] { "tree_id" }, new string[] { "btn_label_id" },(src, destList, rels, formId) => destList?.FirstOrDefault(t => t.code == src.code && t.tree_id == rels[0]));
            await DoAddToDestAsync<t_tree_field>(model, save.AddTreeFields, save.UpdateTreeFields, new string[] { "tree_id" }, new string[] { "field_label_id" }, (src, destList, rels, formId) => destList?.FirstOrDefault(t => t.field_name == src.field_name && t.tree_id == rels[0]));
            #endregion

            var enums = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_enum>(t => t.org_id == model.SrcOrgId);
            var destenums = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_enum>(t => t.org_id == model.DestOrgId);
            var enumDetails = await this.fcpRepository.CommonRepository.GetEntitiesAsync<t_enum_detail>(t => t.org_id == model.SrcOrgId);
            
            enums?.ForEach(t =>
            {
                if (destenums != null && destenums.Any(t1 => t1.enum_name == t.enum_name))
                {
                    return;
                }

                t_enum denum = new t_enum();
                LibSysUtils.CopyObject(denum, t);
                this.SetEntityId(denum);
                denum.org_id = model.DestOrgId;
                save.AddEnums.Add(denum);

                enumDetails?.Where(t1 => t1.enum_id == t.id).ForEach(t1 =>
                {
                    var dden = new t_enum_detail();
                    LibSysUtils.CopyObject(dden, t1);
                    this.SetEntityId(dden, denum.id);
                    dden.org_id = denum.org_id;
                    dden.enum_id = denum.id;
                    save.AddEnumDetails.Add(dden);
                    
                    var srcLabelDetails = model.SrcLabelDetails.Where(t3 => t3.label_id == t1.label_label_id);

                    var pt = new t_label() { org_id = dden.org_id };
                    this.SetEntityId(pt);
                    save.AddLabels.Add(pt);
                    dden.label_label_id = pt.id;

                    if (srcLabelDetails.Any())
                    {
                        srcLabelDetails.ForEach(t4 =>
                          {
                              var p = new t_label_detail() { org_id = dden.org_id, label_id = dden.label_label_id, lang = t4.lang };
                              this.SetEntityId(p, p.label_id);
                              save.AddLabelDetails.Add(p);

                              p.label = t4.label;
                          });
                    }
                    else
                    {

                        var p = new t_label_detail() { org_id = dden.org_id, label_id = dden.label_label_id, lang = this.lang };
                        this.SetEntityId(p, p.label_id);
                        save.AddLabelDetails.Add(p);

                        p.label = dden.label;
                    }
                });
            });

            #region 保存数据
            await this.fcpRepository.CommitChangesByCommonAsync(() =>
            {
                this.fcpRepository.CommonRepository.AddEntities(save.AddForms);
                this.fcpRepository.CommonRepository.AddEntities(save.AddLabels);
                this.fcpRepository.CommonRepository.AddEntities(save.AddLabelDetails);

                this.fcpRepository.CommonRepository.AddEntities(save.AddCharts);

                this.fcpRepository.CommonRepository.AddEntities(save.AddCustoms);

                this.fcpRepository.CommonRepository.AddEntities(save.AddCustomBtns);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEdits);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEditBtns);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEditFields);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEditPanels);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEditFieldFilterFields);
                this.fcpRepository.CommonRepository.AddEntities(save.AddEditFieldFilterGroups);
                this.fcpRepository.CommonRepository.AddEntities(save.AddEditFieldMaps);
                this.fcpRepository.CommonRepository.AddEntities(save.AddEditFieldMapDetails);

                this.fcpRepository.CommonRepository.AddEntities(save.AddSearchs);
                this.fcpRepository.CommonRepository.AddEntities(save.AddSearchFeilds);
                this.fcpRepository.CommonRepository.AddEntities(save.AddSearchFieldFilterFields);
                this.fcpRepository.CommonRepository.AddEntities(save.AddSearchFieldFilterGroups);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTables);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTableBtns);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTableFields);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTableFieldFilterFields);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTableFieldFilterGroups);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTabelFilterFields);
                this.fcpRepository.CommonRepository.AddEntities(save.AddTableFilterGroups);
                this.fcpRepository.CommonRepository.AddEntities(save.AddTablePanel);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTree);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTreeBtns);

                this.fcpRepository.CommonRepository.AddEntities(save.AddTreeFields);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEnums);

                this.fcpRepository.CommonRepository.AddEntities(save.AddEnumDetails);


                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateForms);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateLabels);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateLabelDetails);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateCharts);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateCustoms);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateCustomBtns);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEdits);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditBtns);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditFields);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditPanels);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditFieldFilterFields);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditFieldFilterGroups);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditFieldMaps);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEditFieldMapDetails);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateSearchs);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateSearchFeilds);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateSearchFieldFilterFields);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateSearchFieldFilterGroups);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTables);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTableBtns);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTableFields);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTableFieldFilterFields);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTableFieldFilterGroups);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTabelFilterFields);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTableFilterGroups);
                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTablePanel);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTree);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTreeBtns);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateTreeFields);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEnums);

                this.fcpRepository.CommonRepository.UpdateEntities(save.UpdateEnumDetails);
            });
            #endregion

            if (model.DestFormIds != null && model.DestFormIds.Any())
            {
                await this.fCPService.FormConfigVersionAsync(model.DestOrgId, model.DestFormIds);
            }

            return ret;
        }
    }
}
